package org.jpro.config;

import java.util.Map;

import javax.servlet.Filter;

import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.jpro.modules.system.realm.AuthorizingRealm;
import org.jpro.modules.system.utils.FormAuthenticationCaptchaFilter;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import com.google.common.collect.Maps;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * <P>功能描述 : shiro配置 Apache Shiro 核心通过 Filter 来实现，就好像SpringMvc 通过DispachServlet 来主控制一样。
 * 既然是使用 Filter 一般也就能猜到，是通过URL规则来进行过滤和权限校验，所以我们需要定义一系列关于URL的规则和访问权限。</P>
 * <P>File name : ShiroConfig </P>
 * <P>Author : 王泽浩 </P>
 * <P>E-Mail : 1028625100@qq.com </P>
 * <P>Date : 2017/3/3 下午6:01</P>
 */
@Slf4j
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "spring.shiro")
public class ShiroConfig {

    /**
     * 拦截的地址
     */
    Map<String, String> chainDefinitions = Maps.newLinkedHashMap();

    public ShiroConfig() {
        // 初始话拦截
        chainDefinitions.put("/static/**", "anon");
        chainDefinitions.put("/userfiles/**", "anon");
        chainDefinitions.put("/login", "authc");
        chainDefinitions.put("/logout", "logout");
        chainDefinitions.put("/**", "authc");
    }

    /**
     * 定义Shiro安全管理配置
     * @param authorizingRealm
     * @return
     */
    @Bean(name = "securityManager")
    @DependsOn("authorizingRealm")
    public DefaultWebSecurityManager securityManager(@Qualifier("authorizingRealm") AuthorizingRealm authorizingRealm) {

        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        // 设置自己的登陆授权实现类
        securityManager.setRealm(authorizingRealm);
        return securityManager;

    }

    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * 注意：单独一个ShiroFilterFactoryBean配置是或报错的，以为在
     * 初始化ShiroFilterFactoryBean的时候需要注入：SecurityManager
     * Filter Chain定义说明 1、一个URL可以配置多个Filter，使用逗号分隔 2、当设置多个过滤器时，全部验证通过，才视为通过
     * 3、部分过滤器可指定参数，如perms，roles
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 登陆地址
        shiroFilterFactoryBean.setLoginUrl("/login");

        // 登陆成功地址
        shiroFilterFactoryBean.setSuccessUrl("/");

        // 未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        Map<String, Filter> maps = Maps.newHashMap();
        maps.put("authc", new FormAuthenticationCaptchaFilter());// 验证码拦截器
        shiroFilterFactoryBean.setFilters(maps);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(chainDefinitions);

        return shiroFilterFactoryBean;

    }

    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    @ConditionalOnMissingBean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
        daap.setProxyTargetClass(true);
        return daap;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();
        aasa.setSecurityManager(securityManager);
        return new AuthorizationAttributeSourceAdvisor();
    }

}
